#include "wpsm.h"
#include "assertion.h"

#include <chrono>
#include <iostream>
#include <shared_mutex>
#include <thread>

void test_basic_functionality()
{
    shared_mutex_wp m;
    int shared_value = 0;

    // Writer increments shared_value.
    auto writer = [&]() {
        for (int i = 0; i < 100; ++i) {
            std::unique_lock<shared_mutex_wp> lk(m);
            ++shared_value;
        }
    };

    // Reader checks shared_value is non-decreasing.
    auto reader = [&]() {
        int last = -1;
        for (int i = 0; i < 200; ++i) {
            std::shared_lock<shared_mutex_wp> lk(m);
            int val = shared_value;
            ASSERT(val >= last);
            last = val;
        }
    };

    std::thread w1(writer);
    std::thread w2(writer);
    std::thread r1(reader);
    std::thread r2(reader);

    w1.join();
    w2.join();
    r1.join();
    r2.join();

    ASSERT(shared_value == 200);
    std::cout << "[PASSED] basic functionality test. shared_value=" << shared_value << "\n";
}

void test_writer_priority()
{
    shared_mutex_wp m;
    bool writer_acquired = false;
    bool reader_blocked = false;

    // Lock as writer first, but delay acquisition so readers attempt concurrently.
    std::thread writer([&]() {
        std::this_thread::sleep_for(std::chrono::milliseconds(50));
        std::unique_lock<shared_mutex_wp> lk(m);
        writer_acquired = true;
    });

    std::thread reader([&]() {
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
        std::shared_lock<shared_mutex_wp> lk(m);
        if (!writer_acquired) {
            reader_blocked = true; // reader should block until writer done
        }
    });

    writer.join();
    reader.join();

    ASSERT(writer_acquired);
    ASSERT(reader_blocked);
    std::cout << "[PASSED] writer priority test." << std::endl;
}

int main()
{
    test_basic_functionality();
    test_writer_priority();
    std::cout << "All tests passed." << std::endl;
    return 0;
}
